﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Think.Core;
using Think.Extend;

namespace XQT.Core.TypeEx
{
    /// <summary>
    /// 类型包装扩展
    /// </summary>
    public class TypeWraper
    {
        #region 静态方法
        /// <summary>
        /// 类型包装缓存
        /// </summary>
        static ConcurrentDictionary<Type, TypeWraper> Cache = new ConcurrentDictionary<Type, TypeWraper>();


        /// <summary>
        /// 从缓存获取类型包装，无则新建
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static TypeWraper GetTypeWrap(Type t)
        {
            TypeWraper r = null;
            if (Cache.TryGetValue(t, out r))
            {
                return r;
            }
            r = new TypeWraper(t);
            Cache.TryAdd(t, r);
            return r;
        }
        /// <summary>
        ///根据类型码返回默认值
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public static object TypeCodeDefault(TypeCodeEx code)
        {
            switch (code)
            {
                case TypeCodeEx.Int16:
                case TypeCodeEx.Int32:
                case TypeCodeEx.Int64:
                    return 0;
                case TypeCodeEx.String:
                    return string.Empty;
                case TypeCodeEx.DateTime:
                    return Constants.DefaultDateTime;
                case TypeCodeEx.Boolean:
                    return false;
                case TypeCodeEx.Decimal:
                    return 0.0m;
                case TypeCodeEx.Double:
                    return 0.0d;
                case TypeCodeEx.Single:
                    return 0.0F;
                case TypeCodeEx.Guid:
                    return Guid.Empty;
                default:
                    return null;
            }
        }
        /// <summary>
        /// 取类型默认值
        /// </summary>
        /// <param name="vtype"></param>
        /// <returns></returns>
        public static object TypeDefault(Type vtype)
        {
            var code = GetTypeWrap(vtype).TypeCodeEx;
            var o = TypeCodeDefault(code);
            if (o == null)
            {
                if (vtype == typeof(Guid))
                {
                    o = Guid.Empty;
                }
            }
            return o;
        }
        #endregion

        /// <summary>
        /// 所有属性
        /// </summary>
        public PropertyInfo[] Props = null;
        /// <summary>
        /// 所有方法
        /// </summary>
        public MethodInfo[] Methods = null;
        /// <summary>
        /// 所有构造函数
        /// </summary>
        public ConstructorInfo[] Ctors = null;

        MemberInfo[] _allMembers = null;
        /// <summary>
        /// 所有成员
        /// </summary>
        public MemberInfo[] AllMembers
        {
            get { return _allMembers ?? new MemberInfo[0].Concat(Props).Concat(Methods).Concat(Ctors).ToArray(); }
            set { _allMembers = value; }
        }

        TypeCodeEx _TypeCodeEx = (TypeCodeEx)(-1);

        /// <summary>
        /// 类型代码
        /// </summary>
        public TypeCodeEx TypeCodeEx
        {
            get
            {
                if (_TypeCodeEx < 0)
                {
                    _TypeCodeEx = GetTypeCodeEx();
                }
                return _TypeCodeEx;
            }
        }

        #region 只读字段
        /// <summary>
        /// 系统类型代码
        /// </summary>
        public readonly TypeCode TypeCode;
        /// <summary>
        /// 类型
        /// </summary>
        public readonly System.Type Type;
        /// <summary>
        /// Nullable 包装
        /// </summary>
        public readonly TypeWraper NullableUnderlyingType;
        /// <summary>
        /// 枚举包装
        /// </summary>
        public readonly TypeWraper EnumUnderlyingType;
        /// <summary>
        /// 是否可为null
        /// </summary>
        public readonly bool IsNullable;
        /// <summary>
        /// 是否为Array
        /// </summary>
        public readonly bool IsArray;
        /// <summary>
        /// 是否泛型实现
        /// </summary>
        public readonly bool IsMakeGenericType;
        /// <summary>
        /// 是否数字类型
        /// </summary>
        public readonly bool IsNumberType;
        /// <summary>
        /// 是否值类型
        /// </summary>
        public readonly bool IsValueType;
        /// <summary>
        /// 是否枚举集合
        /// </summary>
        public readonly bool IsEnumrable;
        /// <summary>
        /// 是否存在枚举器
        /// </summary>
        public bool HasIndexer { get; set; }
        /// <summary>
        /// 是否匿名
        /// </summary>
        public bool IsAnonymous;

        #endregion

        internal TypeWraper(Type type)
        {
            Type = type;
            TypeCode = Type.GetTypeCode(type);
            IsAnonymous = type.IsAnonymousType();
            IsArray = type.IsArray;
            IsMakeGenericType = type.IsGenericType && !type.IsGenericTypeDefinition;
            var valueType = Nullable.GetUnderlyingType(type);
            if (valueType != null) //判断可空值类型
            {
                IsNullable = true;
                NullableUnderlyingType = TypeWraper.GetTypeWrap(valueType);
                type = valueType;
            }
            if (type.IsEnum)
            {
                IsNumberType = true;
                EnumUnderlyingType = TypeWraper.GetTypeWrap(Enum.GetUnderlyingType(Type));
            }
            else if (IsNullable)
            {
                IsNumberType = NullableUnderlyingType.IsNumberType;
            }
            else
            {
                IsNumberType = (TypeCode >= TypeCode.SByte && TypeCode <= TypeCode.Decimal);
            }
            IsValueType = Type.IsValueType || ((int)TypeCode > 2 && (int)TypeCode < 100);
            var codeInt = (int)this.TypeCodeEx;
            IsEnumrable = codeInt > 220 && codeInt < 228;
            Props = type.GetProperties();
            Methods = type.GetMethods();
            Ctors = type.GetConstructors();
            HasIndexer = type.IsArray || Props.Any(c => c.Name == "Item") && Methods.Any(c => c.Name == "get_Item");
        }

        /// <summary>
        /// 取扩展类型代码
        /// </summary>
        /// <returns></returns>
        private TypeCodeEx GetTypeCodeEx()
        {
            if (IsNullable) //可空值类型
            {
                return NullableUnderlyingType.GetTypeCodeEx();
            }
            if (Type.IsEnum)
            {
                return TypeCodeEx.Enum;
            }
            if (Type.IsArray)
            {
                return TypeCodeEx.IList;
            }
            if (IsMakeGenericType && Type.Name.StartsWith("<>f__AnonymousType")) //判断匿名类
            {
                return TypeCodeEx.AnonymousType;
            }

            var interfaces = Type.GetInterfaces();
            var length = interfaces.Length;
            for (int i = 0; i < length; i++)
            {
                var inf = interfaces[i];
                if (inf.IsGenericTypeDefinition)
                {

                }
                else if (inf.IsGenericType)
                {
                    inf = inf.GetGenericTypeDefinition();
                }
                else
                {
                    continue;
                }
                if (inf == typeof(IList<>))
                {
                    return TypeCodeEx.IListT;
                }
                else if (inf == typeof(IDictionary<,>))
                {
                    return TypeCodeEx.IDictionaryT;
                }
            }

            if (TypeCode == TypeCode.Object)
            {
                if (Type == typeof(TimeSpan))
                {
                    return TypeCodeEx.TimeSpan;
                }
                else if (Type == typeof(Guid))
                {
                    return TypeCodeEx.Guid;
                }
                else if (Type == typeof(System.Text.StringBuilder))
                {
                    return TypeCodeEx.StringBuilder;
                }
                else if (Type == typeof(System.Data.DataSet))
                {
                    return TypeCodeEx.DataSet;
                }
                else if (Type == typeof(System.Data.DataTable))
                {
                    return TypeCodeEx.DataTable;
                }
                else if (Type == typeof(System.Data.DataView))
                {
                    return TypeCodeEx.DataView;
                }
                else if (Type == typeof(IntPtr))
                {
                    return TypeCodeEx.IntPtr;
                }
                else if (Type == typeof(UIntPtr))
                {
                    return TypeCodeEx.UIntPtr;
                }
                else if (Type == typeof(System.Xml.XmlDocument))
                {
                    return TypeCodeEx.Xml;
                }
                else if (typeof(System.Collections.IList).IsAssignableFrom(Type))
                {
                    return TypeCodeEx.IList;
                }
                else if (typeof(System.Collections.IDictionary).IsAssignableFrom(Type))
                {
                    return TypeCodeEx.IDictionary;
                }
                else if (typeof(System.Data.Common.DbDataReader).IsAssignableFrom(Type))
                {
                    return TypeCodeEx.DbDataReader;
                }
                else if (typeof(System.Data.Common.DbParameter).IsAssignableFrom(Type))
                {
                    return TypeCodeEx.DbParameter;
                }
                else if (typeof(Type).IsAssignableFrom(Type))
                {
                    return TypeCodeEx.Type;
                }
                else if (typeof(ICollection).IsAssignableFrom(Type))
                {
                    return TypeEx.TypeCodeEx.ICollection;
                }
                else if (typeof(ICollection<>).IsAssignableFrom(Type))
                {
                    // return TypeEx.TypeCodeEx.ICollectionT;
                }
                else if (typeof(IEnumerable).IsAssignableFrom(Type))
                {
                    return TypeCodeEx.IEnumerable;
                }
            }
            return (TypeCodeEx)TypeCode;
        }
        /// <summary>
        /// 判断是否包含成员并输出
        /// </summary>
        /// <param name="name"></param>
        /// <param name="mi"></param>
        /// <returns></returns>
        public bool HasMember(string name, out MemberInfo mi)
        {
            mi = this.AllMembers.FirstOrDefault(c => c.Name == name);
            return mi != null;
        }

        /// <summary>
        /// 取属性
        /// </summary>
        /// <param name="name"></param>
        /// <param name="ignorCase"></param>
        /// <returns></returns>
        public PropertyInfo GetProperty(string name, bool ignorCase = false)
        {
            for (int i = 0; i < Props.Length; i++)
            {
                var pi = Props[i];
                if (pi.Name.Equals(name, ignorCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture)) return pi;
            }
            return null;
        }

        /// <summary>
        /// 根据名称及特性标签取属性
        /// </summary>
        /// <param name="name"></param>
        /// <param name="attrType"></param>
        /// <param name="ignorCase"></param>
        /// <returns></returns>
        public PropertyInfo GetProperty(string name, Type attrType, bool ignorCase = false)
        {
            for (int i = 0; i < Props.Length; i++)
            {
                var pi = Props[i];
                var attr = pi.GetCustomAttributes(attrType, true).FirstOrDefault();
                if (attr != null && (attr.MemberCall("Name") + "").Equals(name, ignorCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture))
                {
                    return pi;
                }

            }
            return null;
        }
    }

    /// <summary>
    /// 成员包装
    /// </summary>
    internal class MemberWrap
    {
        MemberInfo _info = null;
        public string Name { get; set; }
        public string FullName { get; set; }
        public MemberWrap(MemberInfo info)
        {
            _info = info;
            if (_info.MemberType == MemberTypes.Property)
            {
                this.ResultType = ((PropertyInfo)info).PropertyType;
            }
        }
        /// <summary>
        /// 返回类型
        /// </summary>
        public Type ResultType
        {
            get;
            set;
        }
        /// <summary>
        /// 参数长度
        /// </summary>
        public int ParamLength { get; set; }
        /// <summary>
        /// 泛型长度
        /// </summary>
        public int GenericLength { get; set; }
        /// <summary>
        /// 参数类型数组
        /// </summary>
        public Type[] ParamsDefiend { get; set; }
        /// <summary>
        /// 泛型参数类型数组
        /// </summary>
        public Type[] GenericParams { get; set; }

        public object Call(object instance, params object[] args)
        {
            return null;
        }
    }



}
